/* * Copyright (C) 2015 drrb * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.github.drrb.rust.netbeans.parsing; import com.github.drrb.rust.netbeans.rustbridge.RustParser; import com.github.drrb.rust.netbeans.rustbridge.RustParseMessage; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Logger; import javax.swing.event.ChangeListener; import javax.swing.text.StyledDocument; import org.netbeans.modules.csl.api.Error; import org.netbeans.modules.csl.spi.DefaultError; import org.netbeans.modules.csl.spi.ParserResult; import org.netbeans.modules.parsing.api.Snapshot; import org.netbeans.modules.parsing.api.Task; import org.netbeans.modules.parsing.spi.ParseException; import org.netbeans.modules.parsing.spi.Parser; import org.netbeans.modules.parsing.spi.SourceModificationEvent; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.text.NbDocument; /** * */ public class NetbeansRustParser extends Parser { private static final Logger LOG = Logger.getLogger(NetbeansRustParser.class.getName()); private final RustParser rustParser = new RustParser(); private RustParser.Result result = RustParser.Result.NONE; private Snapshot snapshot; @Override public void parse(final Snapshot snapshot, Task task, SourceModificationEvent event) { //TODO: if we get segfaults, it's probably to do with this. // we should probably make sure we don't try to access the AST from // a stale (invalidated) result because the AST will have been freed. // (assuming that's actually what ParserResult.invalidate() actually means) this.result.destroy(); this.snapshot = snapshot; this.result = parse(snapshot); } private RustParser.Result parse(Snapshot snapshot) { File file = FileUtil.toFile(snapshot.getSource().getFileObject()); String source = snapshot.getText().toString(); return rustParser.parse(file, source); } @Override public NetbeansRustParserResult getResult(Task task) throws ParseException { return new NetbeansRustParserResult(snapshot, result, getDiagnostics()); } private List<Error> getDiagnostics() { FileObject file = snapshot.getSource().getFileObject(); StyledDocument document = NbDocument.getDocument(file); List<RustParseMessage> parseMessages = result.getParseMessages(); List<Error> diagnostics = new ArrayList<>(parseMessages.size()); for (RustParseMessage message : parseMessages) { int startOffset = NbDocument.findLineOffset(document, message.getStartLine() - 1) + message.getStartCol(); int endOffset = NbDocument.findLineOffset(document, message.getEndLine() - 1) + message.getEndCol(); diagnostics.add(new DefaultError("rust.parse.message", message.getMessage(), message.getMessage(), file, startOffset, endOffset, message.getLevel().severity())); } return diagnostics; } @Override public void addChangeListener(ChangeListener changeListener) { } @Override public void removeChangeListener(ChangeListener changeListener) { } public static class NetbeansRustParserResult extends ParserResult { private final RustParser.Result result; private final AtomicBoolean valid = new AtomicBoolean(true); private final List<Error> diagnostics; public NetbeansRustParserResult(Snapshot snapshot, RustParser.Result result, List<Error> diagnostics) { super(snapshot); this.result = result; this.diagnostics = Collections.unmodifiableList(diagnostics); } public RustParser.Result getResult() throws ParseException { //TODO: is this what we should be doing to ensure people don't // access a released AST? if (!valid.get()) { throw new ParseException(); } return result; } @Override protected void invalidate() { valid.set(false); } @Override public List<? extends Error> getDiagnostics() { return diagnostics; } // // public RustSourceIndex getIndex() { // return getAst().accept(new IndexingVisitor()); // } } }